/*
 * CopyRight(C) Kenbin
 */

#include "lsg_config.h"

static pthread_mutex_t lsg_log_mutex = PTHREAD_MUTEX_INITIALIZER;
static int lsg_log_threadsafe = 0;

struct lsg_log_lock
{
    public:
	lsg_log_lock() {
	    if(lsg_log_threadsafe) pthread_mutex_lock(&lsg_log_mutex);
	}
	~lsg_log_lock() {
	    if(lsg_log_threadsafe) pthread_mutex_unlock(&lsg_log_mutex);
	}
};

static unsigned lsg_log_level = LSG_LOG_INFO;
static char lsg_log_path[256] = {0};
static char lsg_log_prefix[64] = {0};

/* error log OR debug log */
static FILE *lsg_errlog = NULL;
static char lsg_curerrlogtime[12] = {0};

static FILE *lsg_infolog = NULL;
static char lsg_curinfologtime[12] = {0};

void LSG::lsg_set_log_threadsafe(int mode)
{
    lsg_log_threadsafe = mode;
}

void LSG::lsg_set_log_level(unsigned level)
{
    if(level >= LSG_LOG_STDERR && level <= LSG_LOG_DEBUG) {
	lsg_log_level = level;
    }
}

void LSG::lsg_set_log_path(const char *path)
{
    snprintf(lsg_log_path, sizeof(lsg_log_path)-1, "%s", path);
}

void LSG::lsg_set_log_prefix(const char *prefix)
{
    snprintf(lsg_log_prefix, sizeof(lsg_log_prefix)-1, "%s", prefix);
}

static void lsg_get_curlogtime(char *curlogtime)
{
    time_t t = time(NULL);
    struct tm tm;
    struct tm *curtime = localtime_r(&t, &tm);

    int year = 1900 + curtime->tm_year;
    int month = curtime->tm_mon + 1;
    int day = curtime->tm_mday;
    int hour = curtime->tm_hour;

    sprintf(curlogtime, "%04d%02d%02d%02d", 
	    year, month, day, hour);
}

static void lsg_get_localtime(char *localtime)
{
    time_t t = time(NULL);
    struct tm tm;
    struct tm *curtime = localtime_r(&t, &tm);

    int year = 1900 + curtime->tm_year;
    int month = curtime->tm_mon + 1;
    int day = curtime->tm_mday;
    int hour = curtime->tm_hour;
    int min = curtime->tm_min;
    int sec = curtime->tm_sec;

    sprintf(localtime, "%04d-%02d-%02d %02d:%02d:%02d", 
	    year, month, day, hour, min, sec);

}

void LSG::lsg_logging(unsigned level, const char *fmt, ...)
{
    if(level > lsg_log_level) {
	return;
    }

    lsg_log_lock lock;

    if(lsg_log_path[0] == '\0') {
	snprintf(lsg_log_path, sizeof(lsg_log_path)-1, "/tmp");
    }

    if(lsg_log_prefix[0] == '\0') {
	snprintf(lsg_log_prefix, sizeof(lsg_log_prefix)-1, "liblightstorage");
    }

    va_list args;
    char buf[1024] = {0};

    va_start(args, fmt);
    vsnprintf(buf, sizeof(buf)-1, fmt, args);
    va_end(args);

    FILE *log = NULL;
    char logfilename[256] = {0};

    char curlogtime[12] = {0};
    lsg_get_curlogtime(curlogtime);

    char localtime[32] = {0};
    lsg_get_localtime(localtime);

    switch (level) {
	case LSG_LOG_STDERR:
	    log = stderr;
	    break;

	case LSG_LOG_ERR:
	case LSG_LOG_DEBUG:
	    if(strcmp(curlogtime, lsg_curerrlogtime) != 0 
		    || lsg_errlog == NULL || ferror(lsg_errlog) != 0)
	    {
		if(lsg_errlog) {
		    fclose(lsg_errlog);
		}

		sprintf(logfilename, "%s/lsg_%s.err", lsg_log_path, curlogtime);
		mode_t m = umask(0);
		lsg_errlog = fopen(logfilename, "a");
		umask(m);
		strcpy(lsg_curerrlogtime, curlogtime);
	    }

	    log = lsg_errlog;
	    break;

	case LSG_LOG_INFO:
	    if(strcmp(curlogtime, lsg_curinfologtime) != 0 
		    || lsg_infolog == NULL || ferror(lsg_infolog) != 0)
	    {
		if(lsg_infolog) {
		    fclose(lsg_infolog);
		}

		sprintf(logfilename, "%s/lsg_%s.log", lsg_log_path, curlogtime);
		mode_t m = umask(0);
		lsg_infolog = fopen(logfilename, "a");
		umask(m);
		strcpy(lsg_curinfologtime, curlogtime);
	    }

	    log = lsg_infolog;
	    break;

	default:
	    return;
    }

    if(log && !ferror(log)) {
	fprintf(log, "<%d> <%s(%d)> %s %s\n", lsg_log_level, 
		lsg_log_prefix, getpid(), localtime, buf);
    }
}
